#ifndef __EPSILON_3D__TEXTURE_H__
#define __EPSILON_3D__TEXTURE_H__

#include "../types.h"
#include "../strings.h"

class eImage;
class e3dTextureImp;

namespace Epsilon3D {
  class Texture {
  public:
    enum Type {
      InvalidType = 0,

      TexType1D,
      TexType2D,
      TexType3D,
      TexTypeCube,
      TexTypeRect,

      NumTextureTypes,
    };

    enum Unit {
      InvalidUnit = 0,

      TexUnit0,
      TexUnit1,

      TexUnit2,
      TexUnit3,

      TexUnit4,
      TexUnit5,
      TexUnit6,
      TexUnit7,
      
      TexUnit8,
      TexUnit9,
      TexUnit10,
      TexUnit11,

      TexUnit12,
      TexUnit13,
      TexUnit14,
      TexUnit15,

      NumTextureUnits,
    };

           Texture (void) : id (-1), name (NULL), mipmaps (false) { };
  virtual ~Texture (void)
  {
    if (name != NULL) {
      delete [] name;
      name = NULL;
    }

    id = -1;

    destroy ();
  }

  virtual void bind    (Unit unit) = 0;
  virtual void setup   (Unit unit) = 0;
  virtual void enable  (void)      = 0;
  virtual void disable (void)      = 0;

  virtual bool create  (eImage* img, bool mipmap = true) = 0;
  virtual void destroy (void) { };

  virtual Type type    (void) = 0;

protected:
  bool   mipmaps;

private:
  TCHAR* name;
  int    id;
  };
};


class e3dTexture {
public:
           e3dTexture (Epsilon3D::Texture* tex = NULL) : _texture (tex) { };
  virtual ~e3dTexture (void)
  {
    if (_texture != NULL) {
      delete _texture;
      _texture = NULL;
    }
  }

  Epsilon3D::Texture::Type Type (void) {
    if (! _texture)
      return Epsilon3D::Texture::InvalidType;

    return _texture->type ();
  }

  /* Bind the Texture to the specific Sampler Unit. */
  void Bind (Epsilon3D::Texture::Unit unit) {
    if (_texture)
      _texture->bind (unit);
  }

  /* Set the Texture Sampler States (i.e. texgen, filter, etc...) */
  void Setup (Epsilon3D::Texture::Unit unit) {
    if (_texture)
      _texture->setup (unit);
  }

  /* Bind AND Setup this texture on the specific Sampler Unit. */
  void Apply (Epsilon3D::Texture::Unit unit) {
    if (_texture) {
      _texture->bind  (unit);
      _texture->setup (unit);
    }
  }

  void Enable (void) {
    if (_texture)
      _texture->enable ();
  }

  void Disable (void) {
    if (_texture)
      _texture->disable ();
  }

private:
  Epsilon3D::Texture* _texture;
};



#ifdef WIN32
#include <d3d9.h>
//#include <d3dx9.h>
#endif

#include "OpenGL.h"

namespace Epsilon3D {
  class Texture2D : public Texture {
    public:
      Type type (void) {
        return TexType2D;
      }

    private:
  };

#ifdef WIN32
  namespace Direct3D {
    class Texture2D : public Epsilon3D::Texture2D {
      public:
        void bind    (Unit unit);
        void setup   (Unit unit);
        void enable  (void);
        void disable (void);

        bool create  (eImage* img, bool mipmap);
        void destroy (void);

      private:
        LPDIRECT3DTEXTURE9 tex_handle;
    };
  }
#endif

  namespace OpenGL {
    class Texture2D : public Epsilon3D::Texture2D {
      public:
        void bind    (Unit unit);
        void setup   (Unit unit);
        void enable  (void);
        void disable (void);

        bool create  (eImage* img, bool mipmap);
        void destroy (void);

      private:
        GLuint tex_handle;
    };
  }
}

#endif /* __EPSILON_3D__TEXTURE_H__ */
